#ifndef PIDDEVICE_H
#define PIDDEVICE_H

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define _PID_P_POS 0
#define _PID_I_POS 1
#define _PID_D_POS 2
#define _PID_AR_POS 3
#define _PID_T_POS 4

#define PID_DMOD_PV_COM 0
#define PID_DMOD_PV_SEM 1
#define PID_DMOD_PO_SEM 2

	typedef enum
	{
		PID_DWK_NONE = 0,
		PID_DWK_LIN_UP,	   
		PID_DWK_LIN_DN,	   
		PID_DWK_LIN_UP_DN, 
		PID_DWK_LAD_UP,	   
		PID_DWK_LAD_DN,	   
		PID_DWK_LAD_UP_DN, 
	} PID_DWK_TYPE;

	typedef enum
	{
		PID_DZ_MD_NOR = 0, 
		PID_DZ_MD_NEV = 1, 
		PID_DZ_MD_PST = 2, 
	} PID_DZM_TYPE;

	typedef struct
	{
		void (*cal)(void);
		void (*pv_set)(float pv);
		void (*sv_set)(float sv);
		void (*clr)(void);
		void (*dv_clr)(void);
		void (*weak)(float coef);
		void (*update)(uint16_t *tab, float min, float max);
	} pid_api_type;

	typedef struct ind_pid_str
	{
		struct
		{
			uint8_t reset;	
			uint8_t dv_clr; 
		} cmd;

		struct
		{
			PID_DWK_TYPE dv_weak_type;	 
			PID_DZM_TYPE dead_zone_mode; 
			uint8_t i_tab_en;			 
			uint8_t d_limit_en;			 
			uint8_t ctrz_mode;			 
			uint8_t d_mode;				 
			uint8_t iv_suppression;		 
		} func;							 
		struct							 
		{								 
			uint16_t kt_sv;				 
			uint16_t kt_cycle;			 
			uint16_t P, I, D;			 
			uint16_t kt_cnt;			 
		} cfg;							 
		struct							 
		{								 
			float sp_pfac;				 
										 
			struct
			{
				float diff;			
				float coef;			
			} tab[4];				
			float suppression_rang; 
			int16_t iout_min;		
			int16_t iout_max;		
		} icfg;						
		float dead_zone;			
		float d_limit;				
		float ctr_zone_entry;		
		float ctr_zone_quit;		
		float out_min;				
		float out_max;				
		float sv;					
		float pv;					
		struct						
		{							
			float fac;				
			float offset;			
			float flt;				
			int32_t inc_max;		
		} out_cfg;					
		struct						
		{							
			float up_y0;			
			float up_y1;			
			float dn_y0;			
			float dn_y1;			
			float site;				
			float max;				
			float min;				
		} dv_weak;					
		struct                      
		{                           
			float dkp, dki, dkd;    
			void (*func)(struct ind_pid_str* pid); 
		}fuzzy;                     
		struct
		{
			uint8_t ctrz;
			uint8_t d_mode;
		} st;
		int32_t out;   
		float out_adj; 
		struct
		{
			float out_coef;			 
			float out_coef_flt;		 
			float kp, ki, kd, dft;	 
			uint16_t Po, Io, Do, To; 
			float pv_old[2];
			float sv_old;
			float err_old;
			int8_t dir; 
			int8_t st_cal_pulse; 
            uint16_t chk_err_cnt;
		} aux;
		float dv;
		float uk;
		float iken, dken;
		struct
		{
			float lmn;
			float lmn_old;
			float rueck, rest_diff;
		} ddd;
		const pid_api_type *api; 
	} pid_type;

	void pid_clr(pid_type *pid);			  
	void pid_dv_clr(pid_type *pid);			  
	void pid_pv_set(pid_type *pid, float pv); 
	void pid_sv_set(pid_type *pid, float sv); 

	void ind_pid(pid_type *pid);

	void pid_out_weaken(pid_type *pid, float Coef);
	void pid_update(pid_type *pid, uint16_t *ParTab, float DutyMin, float DutyMax);

#define pid_api_make(name, p_obj)                                        \
	static void name##_cal(void);                                        \
	static void name##_pv_set(float pv);                                 \
	static void name##_sv_set(float sv);                                 \
	static void name##_clr(void);                                        \
	static void name##_dv_clr(void);                                     \
	static void name##_weak(float coef);                                 \
	static void name##_update(uint16_t *tab, float min, float max);      \
                                                                         \
	static void name##_cal(void) { ind_pid(p_obj); }                     \
	static void name##_pv_set(float pv) { pid_pv_set(p_obj, pv); }       \
	static void name##_sv_set(float sv) { pid_sv_set(p_obj, sv); }       \
	static void name##_clr(void) { pid_clr(p_obj); }                     \
	static void name##_dv_clr(void) { pid_dv_clr(p_obj); }               \
	static void name##_weak(float coef) { pid_out_weaken(p_obj, coef); } \
	static void name##_update(uint16_t *tab, float min, float max)       \
	{                                                                    \
		pid_update(p_obj, tab, min, max);                                \
	}                                                                    \
                                                                         \
	const pid_api_type name##_pid_api = {                                \
		name##_cal,                                                      \
		name##_pv_set,                                                   \
		name##_sv_set,                                                   \
		name##_clr,                                                      \
		name##_dv_clr,                                                   \
		name##_weak,                                                     \
		name##_update}

#define pid_api_link(name, p_obj) p_obj->api = name##_pid_api
#define pid_api_ref(name, p_obj) extern const simp_pid_api_type name##_pid_api;

#ifdef __cplusplus
}
#endif

#endif 
